#include "OverlappingTemplateMatching.h"


OverlappingTemplateMatching::OverlappingTemplateMatching(bool* bitArray, int bitArraySize) : NistTest(bitArray, bitArraySize)
{
	this->testName = "OverlappingTemplateMatching Test";
}


OverlappingTemplateMatching::~OverlappingTemplateMatching()
{
}

void OverlappingTemplateMatching::start() 
{
	bool inputOK = false;

	while (!inputOK)
	{
		std::cout << "Number of bits to test: (>9999)";
		std::cin >> n;
		if (n < 10000 || n > bitArraySize)
		{
			//inputOK = false;
			std::cout << "Error: The number of bits got to be at least 10000 and max. " << bitArraySize << '\n';
		}
		else
			inputOK = true;
	}

	this->execute(n);
}

void OverlappingTemplateMatching::execute(int n)
{


	/*
	const int N = 8; //Number of blocks
	const int M = (int)floor(n / N); //length of Blocks
	const int K = 5; // Degree of freedom
	this->bitArray;
	this->bitArraySize;
	*/ 


	//Testfall aus Script
	const int N = 5; //Number of blocks
	const int M = (int)floor(n / N); //length of Blocks
	const int K = 2; // Degree of freedom
	n = 50;


	// TODO: first template 001 is from the scripts example -> evaluate result
	// TODO: Datei einlesen ermoeglichen
	int m = 2;  //length of patterns
	//bool bitTemplates[3][3] = { { 0, 0, 1 }, { 0, 1, 1 }, { 0, 1, 0 } };
	bool bitTemplates[1][2] = { {1, 1 }};
	//Pattern findings in a block
	const int V = 5; 
	int* w = new int[V]; 

	int blockStart = 0;
	int blockHits = 0;
	bool patternFound = false;
	const double gamma = (M-m+1)/(pow(2,m));
	const double nu = gamma/2;
	
	//test each template TODO: die 3 sollte so nicht hardgecoded sein. Anzahl der Patterns irgendwie anders einbinden
	for (int j = 0; j < 1; j++) {
		//Test each block
		for (int block = 0; block < N; block++) {
			w[block] = 0; // first test on block  -> initialize with 0;

			//template frame within block?
			blockStart = 0;
			patternFound = false;
			while (blockStart < M - m) {
				//test each bit
				for (int i = 0; i < m; i++) {
					if (bitArray[(block*M) + i] == bitTemplates[j][i]) {
						patternFound = true;
					}
					else
						patternFound = false;
				}

				if (patternFound) blockHits++;
				blockStart++;
				}
			if (blockHits > V-1) {
				w[V - 1]++;
			}	
			else {
				w[blockHits]++;
			}
		}
		// w auswerten
		double pValue = 0.0;
		for (int i = 0; i < V; i++) {
			std::cout << "[" << w[i] << "] ";
			pValue += pow(w[i] -(N*pi(i, nu)), 2) / (N*pi(i, nu));
		}
		std::cout << "chiSquare: " << pValue << "\n";
		pValue = boost::math::gamma_q(V / 2, pValue / 2);
		std::cout << "Result: " << pValue << "\n";
		addResult(pValue);
	}
	printResults();

}

double OverlappingTemplateMatching::pi(int u, double nu) {
	/*Das hier will noch nicht. 
	
	double euler = 2.718281828459045235;
	double pi1 = pow(euler, -1*nu) / pow(2, u);
	double pi2 = 0.0;
	for (int i = 1; i < u + 1; i++) {
		pi2 += nOverK(nu-1, i-1) * pow(nu, i) / (faculty(i));
	}
	return pi1*pi2;
	*/


	//TODO pfui! 
	if (u > 5) return 1;

	switch (u)
		{
		case 0:
			return 0.364091;
			break;
		case 1:
			return 0.185659;
			break;
		case 2 :
			return 0.139381;
			break;
		case 3:
			return 0.100571;
			break;
		case 4:
			return 0.0704323;
			break;
		case 5:
			return 0.139865;
			break;
		}
	}

int OverlappingTemplateMatching::faculty(int n){
	if (n < 2) return 1;
	return n*faculty(n - 1);
}

int OverlappingTemplateMatching::nOverK(int n, int k) {
	if (k == 0) return 1;
	if (n == k) return 1;
	int a = faculty(k);
	int b = faculty(n - k);
	return faculty(n) / ( a*b);
}